﻿using System.Collections;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Text.Unicode;
using ApiLib.Common;
using ApiLib.Utils.Converters;
using Furion.JsonSerialization;

namespace ApiLib.Utils;

/// <summary>
/// 通用工具
/// </summary>
public static class CommonUtil
{
    /// <summary>
    /// 当前时间
    /// </summary>
    /// <returns></returns>
    public static DateTime LocalDateTime()
    {
        try
        {
            var utcTime = DateTime.UtcNow;
            var myZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
            var customDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, myZone);
            return customDateTime;
        }
        catch (Exception e)
        {
            e.Message.LogError();
        }

        return DateTime.Now;
    }

    /// <summary>
    /// 对象自动赋值
    /// </summary>
    /// <param name="model">源类</param>
    /// <param name="target">目标类</param>
    /// <param name="ignores">忽略的字段</param>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T AutoMapping<T>(object? model, T? target, params string[] ignores) where T : new()
    {
        target ??= new T();
        if (model == null)
        {
            return target;
        }

        var properties = model.GetType().GetProperties();
        foreach (var property in properties)
        {
            if (ignores.Contains(property.Name)) continue;
            var targetProperty = target.GetType().GetProperty(property.Name);
            if (targetProperty == null) continue;
            try
            {
                var value = property.GetValue(model, null);
                if (value != null)
                {
                    targetProperty.SetValue(target, value, null);
                }
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return target;
    }

    /// <summary>
    /// 对象比较是否一致，可忽略部分数学
    /// </summary>
    /// <param name="info1">对象1</param>
    /// <param name="info2">对象2</param>
    /// <param name="ignores">忽略的列，不会进行比较</param>
    /// <typeparam name="T">对象类</typeparam>
    /// <returns></returns>
    public static bool Equals<T>(T? info1, T? info2, params string[] ignores)
    {
        if (info1 == null && info2 == null) return true;
        if (info1 == null || info2 == null) return false;

        var flag = true;
        var properties = info1.GetType().GetProperties();
        foreach (var property in properties)
        {
            if (ignores.Contains(property.Name)) continue;
            try
            {
                var value1 = property.GetValue(info1);
                var value2 = property.GetValue(info2);
                if (value1 == null && value2 == null) continue;
                if (!object.Equals(value1, value2))
                {
                    flag = false;
                    break;
                }
            }
            catch (Exception e)
            {
                e.Message.LogError();
                flag = false;
                break;
            }
        }

        return flag;
    }

    /// <summary>
    /// 默认json序列化配置
    /// <remarks>
    /// 使用到Converters：<see cref="ObjectAsPrimitiveConverter"/>,
    /// <see cref="SystemTextJsonConverter.DateTimeConverter"/>,
    /// <see cref="SystemTextJsonConverter.DateTimeNullableConverter"/>
    /// </remarks>
    /// </summary>
    public static readonly JsonSerializerOptions DefaultJsonSerializerOptions = new()
    {
        // PropertyNamingPolicy = JsonNamingPolicy.CamelCase;命名规则：CamelCase驼峰命名
        // IgnoreNullValues = true,已过时，推荐DefaultIgnoreCondition
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, //忽略所有默认值属性
        NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString, //数字的序列化/反序列化方式
        AllowTrailingCommas = true, //允许尾部的逗号
        Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
        PropertyNameCaseInsensitive = true, //大小写不敏感
        Converters =
        {
            new ObjectAsPrimitiveConverter(),
            new SystemTextJsonConverter.DateTimeConverter(),
            new SystemTextJsonConverter.DateTimeNullableConverter()
        }
    };

    /// <summary>
    /// 框架默认的序列化选项
    /// </summary>
    public static JsonSerializerOptions AppJsonSerializerOptions => WebUtil.InitApp
        ? JSON.GetSerializerOptions<JsonSerializerOptions>()
        : DefaultJsonSerializerOptions;

    /// <summary>
    /// 解析枚举类型，无法解析时返回值为0的枚举或者返回0
    /// </summary>
    /// <param name="value">值或者枚举名称</param>
    /// <param name="ignoreCase">忽略大小写</param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? Parse<T>(string value, bool ignoreCase = false) where T : Enum
    {
        if (Enum.TryParse(typeof(T), value, ignoreCase, out var obj))
        {
            if (obj is T t)
            {
                return t;
            }
        }

        return default;
    }

    /*
    /// <summary>
    /// MD5字符串加密
    /// </summary>
    /// <param name="txt"></param>
    /// <returns>加密后字符串</returns>
    public static string Md5(string txt)
    {
        var buffer = Encoding.UTF8.GetBytes(txt);
        //开始加密
        return Md5(buffer);
    }

    /// <summary>
    /// MD5加密
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns>加密后字符串</returns>
    public static string Md5(byte[] bytes)
    {
        using var mi = MD5.Create();
        //开始加密
        var buffer = mi.ComputeHash(bytes);
        var sb = new StringBuilder();
        foreach (var b in buffer)
        {
            sb.Append(b.ToString("x2"));
        }

        return sb.ToString();
    }

    /// <summary>
    /// Base64加密
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public static string Base64Encode(string text)
    {
        var bytes = Encoding.UTF8.GetBytes(text);
        return Convert.ToBase64String(bytes);
    }

    /// <summary>
    /// Base64解密
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public static string Base64Decode(string text)
    {
        var bytes = Convert.FromBase64String(text);
        return Encoding.UTF8.GetString(bytes);
    }*/

    /// <summary>
    /// 抛出Action验证异常
    /// </summary>
    /// <param name="msg">异常信息</param>
    /// <returns><see cref="MyActionException"/></returns>
    public static MyActionException ActionException(string msg)
    {
        WebUtil.LogExp(msg);
        return new MyActionException(msg);
    }
    

    /// <summary>
    /// 获取符合条件的枚举类型
    /// </summary>
    /// <param name="predicate"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? GetEnum<T>(Predicate<T> predicate) where T : struct, Enum
    {
        var enums = Enum.GetValues<T>().ToList();
        return enums.Get(predicate);
    }
}

/// <summary>
/// 通用扩展
/// </summary>
public static class CommonExtend
{
    /// <summary>
    /// Predicate=&gt;Func
    /// </summary>
    /// <param name="predicate"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Func<T, bool> ToFunc<T>(this Predicate<T> predicate)
    {
        Func<T, bool> func = predicate.Invoke;
        return func;
    }

    /// <summary>
    /// Predicate=&gt;Expression
    /// </summary>
    /// <param name="predicate"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Expression<Func<T, bool>> ToExp<T>(this Predicate<T> predicate)
    {
        Expression<Func<T, bool>> exp = arg => predicate.Invoke(arg);
        return exp;
    }

    /// <summary>
    /// Func=&gt;Expression
    /// </summary>
    /// <param name="func"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Expression<Func<T, bool>> ToExp<T>(this Func<T, bool> func)
    {
        Expression<Func<T, bool>> exp = arg => func.Invoke(arg);
        return exp;
    }
}

/// <summary>
/// 字符串扩展
/// </summary>
public static partial class StringUtil
{
    #region 判断

    /// <summary>
    /// 判断是否为空
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool NullOrEmpty([NotNullWhen(false)] this string? value)
    {
        return value is null or "";
    }

    /// <summary>
    /// 判断是否为空
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
    {
        return value.NullOrEmpty();
    }

    /// <summary>
    /// 判断是否为空
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool NotNullOrEmpty([NotNullWhen(true)] this string? value)
    {
        return !value.NullOrEmpty();
    }

    /// <summary>
    /// 判断是否为空
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsNotNullOrEmpty([NotNullWhen(true)] this string? value)
    {
        return !value.NullOrEmpty();
    }

    /// <summary>
    /// 判断是否包含子项
    /// </summary>
    /// <param name="text">文本，以{",", "-", "_", "、", "，"}分隔</param>
    /// <param name="item">子项</param>
    /// <returns></returns>
    public static bool ContainsItem(this string? text, string item)
    {
        if (text == null || text.IsNullOrEmpty() || item.IsNullOrEmpty())
        {
            return false;
        }

        var seps = new[] { ",", "-", "_", "、", "，" };
        var spitChar = "";
        foreach (var sep in seps)
        {
            if (!text.Contains(sep)) continue;
            spitChar = sep;
            break;
        }

        return text.Split(spitChar).Contains(item);
    }

    /// <summary>
    /// 字符串比较
    /// </summary>
    /// <param name="content"></param>
    /// <param name="otherStr"></param>
    /// <param name="ignoreCase">是否忽略大小写</param>
    /// <returns></returns>
    public static bool Equals(this string content, string otherStr, bool ignoreCase = false)
    {
        return content.Equals(otherStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
    }


    /// <summary>
    /// 判断字符串是否为空
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns></returns>
    public static bool IsBlank(this string? text)
    {
        if (text.NullOrEmpty())
        {
            return true;
        }

        return text.Trim().Length == 0;
    }

    #endregion

    #region 转换

    /// <summary>
    /// 字符串转驼峰命名：把-或者_后面首字母大写
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string ToUnderLine(this string str)
    {
        if (string.IsNullOrEmpty(str.Trim()))
        {
            return "";
        }

        var charArray = str.ToCharArray();
        var output = "";
        for (var i = 0; i < charArray.Length; i++)
        {
            if (charArray[i] >= 'A' && charArray[i] <= 'Z')
            {
                if (i != 0)
                {
                    output += '_';
                }

                output += (char)(charArray[i] + 32);
            }
            else
            {
                output += charArray[i];
            }
        }

        return output;
    }

    /// <summary>
    /// 驼峰命名转字符串：把-或者_后面首字母大写
    /// </summary>
    /// <param name="str"></param>
    /// <param name="includeFirst">是否包含首字母，默认false</param>
    /// <returns></returns>
    public static string ToCamelCase(this string str, bool includeFirst = true)
    {
        if (string.IsNullOrEmpty(str.Trim()))
        {
            return "";
        }

        var charArray = str.ToCharArray();
        for (var i = 0; i < charArray.Length - 1; i++)
        {
            if (charArray[i] == '-' || charArray[i] == '_')
            {
                if (charArray[i + 1] >= 'a' && charArray[i + 1] <= 'z')
                {
                    charArray[i + 1] = (char)(charArray[i + 1] - 32);
                }
            }
        }

        if (includeFirst && charArray[0] >= 'a' && charArray[0] <= 'z')
        {
            charArray[0] = (char)(charArray[0] - 32);
        }

        var cs = charArray.Where(c => c != '-' && c != '_');
        return string.Join("", cs);
    }

    /// <summary>
    /// 替换全部，正则表达式
    /// </summary>
    /// <param name="str">原始字符串</param>
    /// <param name="pattern">正则表达式</param>
    /// <param name="newVal">替换成新的字符串</param>
    /// <returns></returns>
    public static string ReplaceAll(this string str, string pattern, string newVal)
    {
        return Regex.Replace(str, pattern, newVal);
    }

    /// <summary>
    /// 字符串截取
    /// </summary>
    /// <param name="str">原始字符串</param>
    /// <param name="start">开始位置</param>
    /// <param name="end">结束位置</param>
    /// <returns></returns>
    public static string SubstringJ(this string str, int start, int end)
    {
        return str.Substring(start, end - start);
    }

    /// <summary>
    /// 字符串编码转换
    /// </summary>
    /// <param name="content">字符串</param>
    /// <param name="srcEncode">原编码</param>
    /// <param name="toEncode">目标编码</param>
    /// <returns></returns>
    public static string Convert(this string content, Encoding srcEncode, Encoding toEncode)
    {
        return toEncode.GetString(Encoding.Convert(srcEncode, toEncode, srcEncode.GetBytes(content)));
    }

    /// <summary>
    /// 获取文本，将字节数组解码为某个编码的字符串，通常用于处理文本数据
    /// </summary>
    /// <param name="bytes">字节数组</param>
    /// <param name="encoding">编码：默认UTF8</param>
    /// <returns></returns>
    public static string GetString(this byte[] bytes, Encoding? encoding = null)
    {
        encoding ??= Encoding.UTF8;
        return encoding.GetString(bytes);
    }

    /// <summary>
    /// 获取文本，用于生成字节数组的十六进制表示
    /// </summary>
    /// <param name="bytes">字节数组</param>
    /// <param name="upperTrance">转大写</param>
    /// <returns></returns>
    public static string GetBitConverterString(this byte[] bytes, bool upperTrance = true)
    {
        var converterString = BitConverter.ToString(bytes).Replace("-", "");
        return upperTrance ? converterString.ToUpperInvariant() : converterString;
    }

    /// <summary>
    /// 重复字符串
    /// </summary>
    /// <param name="text">文本</param>
    /// <param name="count">字符串重复次数，默认2</param>
    /// <returns></returns>
    public static string Repeat(this string text, int count = 2)
    {
        var result = "";
        for (var i = 0; i < count; i++)
        {
            result += text;
        }

        return result;
    }

    /// <summary>
    /// 字符串缩进
    /// </summary>
    /// <param name="text">文本</param>
    /// <param name="count">缩进字符串数量，默认4</param>
    /// <param name="isZh">中文缩进，默认false</param>
    /// <returns></returns>
    public static string Indent(this string? text, int count = 4, bool isZh = false)
    {
        if (text.NullOrEmpty())
        {
            return "";
        }

        var space = isZh ? "  " : " ";
        switch (count)
        {
            case > 0:
            {
                var spaces = space.Repeat(count);
                var lines = text.Lines().ToList();
                for (var i = 0; i < lines.Count; i++)
                {
                    lines[i] = spaces + lines[i];
                }

                return string.Join("\n", lines);
            }
            case < 0:
            {
                var less = -count;
                var lines = text.Lines().ToList();
                for (var i = 0; i < lines.Count; i++)
                {
                    lines[i] = lines[i].Length <= less ? "" : lines[i][less..];
                }

                return string.Join("\n", lines);
            }
            default:
                return text;
        }
    }

    /// <summary>
    /// 字符串转变
    /// </summary>
    /// <param name="text">文本</param>
    /// <param name="func"></param>
    /// <returns></returns>
    public static string? Transform(this string? text, Func<string?, string?> func)
    {
        return func.Invoke(text);
    }

    /// <summary>
    /// 清理html标签
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns></returns>
    public static string ClearHtml(this string text)
    {
        return Regex.Replace(text, @"<[^>]*>", string.Empty);
    }

    #endregion


    /// <summary>
    /// 字符串转时间
    /// </summary>
    /// <param name="dateTimeStr"></param>
    /// <param name="format">yyyy-MM-dd HH:mm:ss</param>
    /// <returns></returns>
    public static DateTime? ToDateTime(this string dateTimeStr, string? format = null)
    {
        if (string.IsNullOrEmpty(format))
        {
            format = "yyyy-MM-dd HH:mm:ss";
        }

        try
        {
            return DateTime.ParseExact(dateTimeStr, format, CultureInfo.CurrentCulture);
        }
        catch (Exception e)
        {
            return default;
        }
    }

    /// <summary>
    /// 字符串转时间
    /// </summary>
    /// <param name="dateTimeStr"></param>
    /// <param name="format">yyyy-MM-dd HH:mm:ss</param>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static bool TryToDateTime(this string dateTimeStr, string? format, out DateTime? dt)
    {
        dt = dateTimeStr.ToDateTime(format);
        return dt != null;
    }

    /// <summary>
    /// 获取字节数组
    /// </summary>
    /// <param name="text">文本</param>
    /// <param name="encoding">编码：默认UTF8</param>
    /// <returns></returns>
    public static byte[] GetBytes(this string text, Encoding? encoding = null)
    {
        encoding ??= Encoding.UTF8;
        return encoding.GetBytes(text);
    }


    /// <summary>
    /// 返回由行终止符分隔的字符串数组
    /// </summary>
    /// <param name="text">文本</param>
    /// <returns></returns>
    public static string[] Lines(this string text)
    {
        return text.Split("\n");
    }
}

/// <summary>
/// 字符串工具
/// </summary>
public static partial class StringUtil
{
    /// <summary>
    /// 计算两个字符串的Levenshtein距离<br/>
    /// 允许三种基本操作：插入、删除、替换。<br/>
    /// Levenshtein 距离指的是，通过插入、删除、替换操作，将一个字符串转变成另一个字符串所需的最少操作次数。当这个距离小于或等于设定的阈值时，就可以认为这两个字符串是相似的。
    /// </summary>
    /// <param name="s"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static int LevenshteinDistance(string s, string t)
    {
        if (string.IsNullOrEmpty(s)) return t?.Length ?? 0;
        if (string.IsNullOrEmpty(t)) return s.Length;

        int n = s.Length;
        int m = t.Length;
        int[,] d = new int[n + 1, m + 1];

        // 初始化矩阵
        for (int i = 0; i <= n; d[i, 0] = i++) ;
        for (int j = 0; j <= m; d[0, j] = j++) ;

        // 填充矩阵
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                d[i, j] = Math.Min(
                    Math.Min(d[i - 1, j] + 1, // 删除
                        d[i, j - 1] + 1), // 插入
                    d[i - 1, j - 1] + cost); // 替换
            }
        }

        return d[n, m];
    }

    /// <summary>
    /// 优化性能的 Levenshtein 算法（Damerau-Levenshtein）<br/>
    /// 在 Levenshtein 基础上增加了 相邻字符交换（Transposition）作为第四种操作。例如：将 ab 转换为 ba 只需 1 次交换操作（Levenshtein 需要 2 次操作：删除 + 插入）。<br/>
    /// 这个算法对基础的 Levenshtein 算法进行了扩展，它把相邻字符的交换也当作是一种基本操作，这样能更精准地处理实际应用中的拼写错误。
    /// </summary>
    /// <param name="s"></param>
    /// <param name="t"></param>
    /// <returns></returns>
    public static int DamerauLevenshteinDistance(string s, string t)
    {
        if (string.IsNullOrEmpty(s)) return t?.Length ?? 0;
        if (string.IsNullOrEmpty(t)) return s.Length;

        int n = s.Length;
        int m = t.Length;
        int[,] d = new int[n + 1, m + 1];

        // 初始化矩阵
        for (int i = 0; i <= n; d[i, 0] = i++) ;
        for (int j = 0; j <= m; d[0, j] = j++) ;

        // 填充矩阵
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                d[i, j] = Math.Min(
                    Math.Min(d[i - 1, j] + 1, // 删除
                        d[i, j - 1] + 1), // 插入
                    d[i - 1, j - 1] + cost); // 替换

                // 检查相邻字符的交换
                if (i > 1 && j > 1 && s[i - 1] == t[j - 2] && s[i - 2] == t[j - 1])
                {
                    d[i, j] = Math.Min(d[i, j], d[i - 2, j - 2] + cost);
                }
            }
        }

        return d[n, m];
    }

    /// <summary>
    /// 比较字符串，允许maxDifferences个字符不同
    /// </summary>
    /// <param name="str1"></param>
    /// <param name="str2"></param>
    /// <param name="maxDifferences"></param>
    /// <returns></returns>
    public static bool AreStringsSimilar(string str1, string str2, int maxDifferences)
    {
        return LevenshteinDistance(str1, str2) <= maxDifferences;
    }

    /// <summary>
    /// 比较字符串，允许maxDifferences个字符不同
    /// </summary>
    /// <param name="str1"></param>
    /// <param name="str2"></param>
    /// <param name="maxDifferences"></param>
    /// <returns></returns>
    public static bool AreStringsSimilarDamerau(string str1, string str2, int maxDifferences)
    {
        return DamerauLevenshteinDistance(str1, str2) <= maxDifferences;
    }
}

/// <summary>
/// DataTable扩展
/// </summary>
public static partial class DataTableUtil
{
    /// <summary>
    /// DataTable转字典
    /// </summary>
    /// <param name="dt"></param>
    /// <param name="ignoreNull">是否忽略空值，默认false</param>
    /// <returns></returns>
    public static List<Dictionary<string, object?>> ToListDictionary(this DataTable dt, bool ignoreNull = false)
    {
        var list = new List<Dictionary<string, object?>>();
        foreach (DataRow dr in dt.Rows)
        {
            var result = new Dictionary<string, object?>();
            foreach (DataColumn dc in dt.Columns)
            {
                var value = dr[dc] != DBNull.Value ? dr[dc] : null;
                if (!ignoreNull || value != null)
                {
                    result.Add(dc.ColumnName, value);
                }
            }

            list.Add(result);
        }

        return list;
    }

    /// <summary>
    /// DataTable转对象
    /// </summary>
    /// <param name="dataTable"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static List<T> ToList<T>(this DataTable dataTable) where T : new()
    {
        var list = new List<T>();
        var properties = typeof(T).GetProperties();
        foreach (DataRow row in dataTable.Rows)
        {
            var entity = new T();
            foreach (var property in properties)
            {
                var value = row[property.Name];
                if (property.PropertyType == typeof(int))
                {
                    property.SetValue(entity, int.Parse(value.ToString() ?? string.Empty), null);
                }
                else if (property.PropertyType == typeof(DateTime))
                {
                    property.SetValue(entity, DateTime.Parse(value.ToString() ?? string.Empty), null);
                }
                else
                {
                    property.SetValue(entity, value, null);
                }
            }

            list.Add(entity);
        }

        return list;
    }
}

public static partial class DataTableUtil
{
    
}
/// <summary>
/// 集合扩展
/// </summary>
public static partial class CollectionUtil
{
    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="list"></param>
    /// <param name="pageIndex">页码</param>
    /// <param name="pageSize">分页大小</param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static List<T> ToPageList<T>(this IEnumerable<T> list, int pageIndex, int pageSize)
    {
        return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    }

    /// <summary>
    /// 分页
    /// </summary>
    /// <param name="list"></param>
    /// <param name="pageIndex">页码</param>
    /// <param name="pageSize">分页大小</param>
    /// <param name="pageCount">总数</param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static List<T> ToPageList<T>(this ICollection<T> list, int pageIndex, int pageSize, out int pageCount)
    {
        var count = list.Count;
        pageCount = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
        return list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
    }

    /// <summary>
    /// 集合分页
    /// </summary>
    /// <param name="list">集合</param>
    /// <param name="pageSize">每页大小</param>
    /// <param name="action">操作</param>
    /// <typeparam name="T"></typeparam>
    public static void PageEach<T>(this List<T> list, int pageSize, Action<List<T>> action)
    {
        var pageCount = list.Count % pageSize == 0 ? list.Count / pageSize : list.Count / pageSize + 1;
        for (var i = 1; i <= pageCount; i++)
        {
            var pageList = list.ToPageList(i, pageSize);
            action.Invoke(pageList);
        }
    }

    /// <summary>
    /// 集合分页
    /// </summary>
    /// <param name="list">集合</param>
    /// <param name="pageSize">每页大小</param>
    /// <param name="action">操作</param>
    /// <typeparam name="T"></typeparam>
    public static async Task PageEach<T>(this List<T> list, int pageSize, Func<List<T>, Task> action)
    {
        var pageCount = list.Count % pageSize == 0 ? list.Count / pageSize : list.Count / pageSize + 1;
        for (var i = 1; i <= pageCount; i++)
        {
            var pageList = list.ToPageList(i, pageSize);
            await action(pageList);
        }
    }

    /// <summary>
    /// 集合排序（暂不可用）
    /// </summary>
    /// <param name="list">集合</param>
    /// <param name="func">排序方式，默认采用id升序，func返回{{nameof(字段),true}}，其中true升序，false降序</param>
    /// <typeparam name="T"></typeparam>
    [Obsolete]
    public static List<T> QSort<T>(this List<T> list, Func<T, SortedList<string, bool>>? func = null) where T : new()
    {
        var sortedList = func?.Invoke(new T());
        var props = new SortedList<PropertyInfo, bool>();
        if (sortedList == null || sortedList.Count == 0)
        {
            var field = typeof(T).GetProperty("Id") ?? typeof(T).GetProperty("ID") ?? typeof(T).GetProperty("id");
            if (field != null)
            {
                props.Add(field, true);
            }
        }
        else
        {
            foreach (var (key, value) in sortedList)
            {
                var propertyInfo = typeof(T).GetProperty(key);
                if (propertyInfo != null)
                {
                    props.Add(propertyInfo, value);
                }
            }
        }

        IOrderedEnumerable<T>? orderedEnumerable = null;
        foreach (var (key, value) in props)
        {
            Func<T, object?> func2 = arg => key.GetValue(arg);
            if (orderedEnumerable == null)
            {
                orderedEnumerable = value ? list.OrderBy(func2) : list.OrderByDescending(func2);
            }
            else
            {
                orderedEnumerable = value ? orderedEnumerable.ThenBy(func2) : orderedEnumerable.ThenByDescending(func2);
            }
        }

        return orderedEnumerable?.ToList() ?? list.ToList();
    }

    /// <summary>
    /// 集合排序（暂不可用）
    /// </summary>
    /// <param name="list">集合</param>
    /// <param name="func">排序方式，默认采用id升序，func返回{nameof(字段)=true}，其中true升序，false降序</param>
    /// <typeparam name="T"></typeparam>
    [Obsolete]
    public static List<T> QSort<T>(this List<T> list, Func<T, object>? func = null) where T : new()
    {
        var obj = func?.Invoke(new T());
        var propertyInfos = obj?.GetType().GetProperties();
        var props = new SortedList<PropertyInfo, bool>();
        if (propertyInfos == null || propertyInfos.Length == 0)
        {
            var field = typeof(T).GetProperty("Id") ?? typeof(T).GetProperty("ID") ?? typeof(T).GetProperty("id");
            if (field != null)
            {
                props.Add(field, true);
            }
        }
        else
        {
            foreach (var prop in propertyInfos)
            {
                var propertyInfo = typeof(T).GetProperty(prop.Name);
                if (propertyInfo != null)
                {
                    var fieldValue = prop.GetFieldValue<bool>(prop);
                    props.Add(propertyInfo, fieldValue);
                }
            }
        }

        IOrderedEnumerable<T>? order = null;
        foreach (var (key, value) in props)
        {
            Func<T, object?> func2 = arg => key.GetValue(arg);
            if (order == null)
            {
                order = value ? list.OrderBy(func2) : list.OrderByDescending(func2);
            }
            else
            {
                order = value ? order.ThenBy(func2) : order.ThenByDescending(func2);
            }
        }

        return order?.ToList() ?? list.ToList();
    }

    /// <summary>
    /// 全部添加
    /// </summary>
    /// <param name="set">set集合</param>
    /// <param name="list"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static void AddAll<T>(this HashSet<T> set, IEnumerable<T> list)
    {
        foreach (var item in list)
        {
            set.Add(item);
        }
    }

    /// <summary>
    /// 是否为空
    /// </summary>
    /// <param name="enumerable"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty([NotNullWhen(false)] this IEnumerable? enumerable)
    {
        return enumerable is null or IList { Count: 0 };
    }

    /// <summary>
    /// 是否为空
    /// </summary>
    /// <param name="list"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static bool IsNullOrEmpty<T>([NotNullWhen(false)] this List<T>? list)
    {
        return list == null || list.Count == 0;
    }

    /// <summary>
    /// 是否为空
    /// </summary>
    /// <param name="array"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static bool IsNullOrEmpty<T>([NotNullWhen(false)] this T[]? array)
    {
        return array == null || array.Length == 0;
    }

    /// <summary>
    /// 拼接
    /// </summary>
    /// <param name="list"></param>
    /// <param name="separator"></param>
    /// <returns></returns>
    public static string ToJoin(this IEnumerable<string> list, string separator)
    {
        return string.Join(separator, list);
    }

    /// <summary>
    /// 转换成DataTable
    /// </summary>
    /// <param name="list"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static DataTable ToDataTable<T>(this IEnumerable<T> list)
    {
        var table = new DataTable(typeof(T).Name);
        var propertyInfos = typeof(T).GetProperties();
        foreach (var propertyInfo in propertyInfos)
        {
            table.Columns.Add(propertyInfo.Name);
        }

        foreach (var item in list)
        {
            if (item is null)
            {
                continue;
            }

            var row = table.NewRow();
            foreach (var propertyInfo in propertyInfos)
            {
                var value = item.GetFieldValue(propertyInfo.Name);
                row[propertyInfo.Name] = value;
            }

            table.Rows.Add(row);
        }

        return table;
    }

    /// <summary>
    /// 转换成集合
    /// </summary>
    /// <param name="table"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static List<T> ToList<T>(this DataTable table) where T : new()
    {
        var propertyInfos = typeof(T).GetProperties();
        var list = new List<T>();
        foreach (DataRow row in table.Rows)
        {
            var foo = new T();
            foreach (var property in propertyInfos)
            {
                foo.SetFieldValue(property.Name, row[property.Name]);
            }

            list.Add(foo);
        }

        return list;
    }

    /// <summary>
    /// 随机获取一个
    /// </summary>
    /// <param name="list"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? RandomOne<T>(this List<T>? list)
    {
        if (list == null || list.Count == 0)
        {
            return default;
        }

        var random = new Random();
        var next = random.Next(list.Count);
        return list[next];
    }


    /// <summary>
    /// 移除
    /// </summary>
    /// <param name="list"></param>
    /// <param name="items"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static int RemoveAll<T>(this List<T> list, params T[] items)
    {
        var count = 0;
        foreach (var item in items)
        {
            count += list.Remove(item) ? 1 : 0;
        }

        return count;
    }

    /// <summary>
    /// 移除
    /// </summary>
    /// <param name="list"></param>
    /// <param name="items"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static int RemoveAll<T>(this List<T> list, IList<T> items)
    {
        return list.RemoveAll(items.ToArray());
    }

    /// <summary>
    /// 获取枚举类型
    /// </summary>
    /// <param name="list"></param>
    /// <param name="predicate"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? Get<T>(this List<T> list, Predicate<T> predicate) where T : struct
    {
        foreach (var item in list)
        {
            if (predicate.Invoke(item))
            {
                return item;
            }
        }

        return null;
    }

    /// <summary>
    /// KeyValuePair集合转字典
    /// </summary>
    /// <param name="pairs"></param>
    /// <typeparam name="TK"></typeparam>
    /// <typeparam name="TV"></typeparam>
    /// <returns></returns>
    public static Dictionary<TK, TV> ToDictionary<TK, TV>(this List<KeyValuePair<TK, TV>> pairs) where TK : notnull
    {
        return pairs.ToDictionary(p => p.Key, p => p.Value);
    }

    /// <summary>
    /// 遍历数组
    /// </summary>
    /// <param name="array"></param>
    /// <param name="action"></param>
    /// <typeparam name="T"></typeparam>
    public static void ForEach<T>(this T[] array, Action<T> action)
    {
        foreach (var x1 in array)
        {
            action.Invoke(x1);
        }
    }

    /// <summary>
    /// 遍历数组
    /// </summary>
    /// <param name="array"></param>
    /// <param name="action"></param>
    /// <typeparam name="T"></typeparam>
    public static async Task ForEach<T>(this T[] array, Func<T, Task> action)
    {
        foreach (var x1 in array)
        {
            await action(x1);
        }
    }

    /// <summary>
    /// 获取子项的类型
    /// </summary>
    /// <param name="enumerable"></param>
    /// <returns></returns>
    public static Type GetItemType(this IEnumerable enumerable)
    {
        if (enumerable is IList { Count: > 0 } list)
        {
            var item = list[0];
            if (item != null)
            {
                return item.GetType();
            }
        }

        return enumerable.GetType().GenericTypeArguments[0];
    }
}
public static partial class CollectionUtil{}
/// <summary>
/// 字典扩展
/// </summary>
public static partial class DictionaryUtil
{
    /// <summary>
    /// 赋值，如果不存在key，就新增
    /// </summary>
    /// <param name="dict">字典</param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public static void Put<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        where TKey : notnull
    {
        dict[key] = value;
    }

    /// <summary>
    /// 取值
    /// </summary>
    /// <param name="dict">字典</param>
    /// <param name="key">键</param>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <returns></returns>
    public static TValue? Get<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TKey : notnull
    {
        return dict.TryGetValue(key, out var value) ? value : default;
    }

    /// <summary>
    /// 将字典集合转换为动态对象
    /// </summary>
    /// <param name="dict">属性/属性值字典集合</param>
    /// <returns></returns>
    public static dynamic? ToExpandoObject(this IDictionary<string, object?>? dict)
    {
        if (dict == null) return null;
        IDictionary<string, object?> expandoObject = new ExpandoObject();
        foreach (var pair in dict)
        {
            expandoObject.Add(pair);
        }

        return expandoObject as ExpandoObject;
    }

    /// <summary>
    /// 转换为动态对象
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static ExpandoObject ToExpandoObject(this object obj)
    {
        dynamic expando = new ExpandoObject();
        var expandoDict = (IDictionary<string, object>)expando;

        foreach (var property in obj.GetType().GetProperties())
        {
            expandoDict[property.Name] = property.GetFieldValue(obj) ?? "";
        }

        return (expando as ExpandoObject)!;
    }

    /// <summary>
    /// 字典添加对象
    /// </summary>
    /// <param name="dict">字典</param>
    /// <param name="obj">对象</param>
    /// <param name="ignores">忽略</param>
    /// <returns></returns>
    public static Dictionary<string, object> Add(this Dictionary<string, object>? dict, object obj,
        params string[] ignores)
    {
        dict ??= new Dictionary<string, object>();
        var properties = obj.GetType().GetProperties();
        foreach (var property in properties)
        {
            if (ignores.Contains(property.Name)) continue;
            try
            {
                var value = property.GetValue(obj, null);
                dict.Add(property.Name, value ?? "");
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return dict;
    }

    /// <summary>
    /// 获取值
    /// </summary>
    /// <param name="dict"></param>
    /// <param name="key"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? GetValue<T>(this IDictionary<string, object?>? dict, string key)
    {
        return dict != null &&
               dict.TryGetValue(key, out var obj) &&
               obj is T t
            ? t
            : default;
    }

    /// <summary>
    /// 对象转换
    /// </summary>
    /// <param name="obj"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    /// <exception cref="MyActionException"></exception>
    public static T? CastToObj<T>(this IDictionary<string, object?>? obj)
    {
        if (obj == null)
        {
            return default;
        }

        var instance = typeof(T).GetInstance<T>();
        if (instance == null)
        {
            throw CommonUtil.ActionException("对象初始化失败");
        }

        foreach (var (key, value) in obj)
        {
            instance.SetFieldValue(key, value);
        }

        return instance;
    }

    /// <summary>
    /// 对象转换
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    /// <exception cref="MyActionException"></exception>
    public static object? CastToObj(this IDictionary<string, object?>? obj, Type type)
    {
        if (obj == null)
        {
            return default;
        }

        var instance = type.GetInstance();
        if (instance == null)
        {
            throw CommonUtil.ActionException("对象初始化失败");
        }

        foreach (var (key, value) in obj)
        {
            instance.SetFieldValue(key, value);
        }

        return instance;
    }
}
public static partial class DictionaryUtil{}
/// <summary>
/// 时间扩展
/// </summary>
public static partial class DateTimeUtil
{
    /// <summary>
    /// 时间格式化
    /// </summary>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static string ToCommonFormat(this DateTime dt)
    {
        return dt.ToString("yyyy-MM-dd HH:mm:ss");
    }

    /// <summary>
    /// 时间格式化
    /// </summary>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static string ToCommonFormat(this DateTime? dt)
    {
        return dt == null ? "" : dt.Value.ToCommonFormat();
    }

    /// <summary>
    /// 获得日期
    /// </summary>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static DateTime ToShortDate(this DateTime dt)
    {
        var date = new DateTime(dt.Year, dt.Month, dt.Day);
        return date;
    }

    /// <summary>
    /// 获取开始时间
    /// </summary>
    /// <param name="timeType">Day、Week、Month、Year</param>
    /// <param name="now"></param>
    /// <returns></returns>
    public static string GetTimeStartByType(this DateTime now, string timeType = "month")
    {
        return timeType.ToLower() switch
        {
            "week" => now.AddDays((7 - (int)now.DayOfWeek) % 7 - 7 + 1).ToString("yyyy-MM-dd 00:00:00"),
            "month" => now.AddDays(-now.Day + 1).ToString("yyyy-MM-dd 00:00:00"),
            "year" => now.AddDays(-now.DayOfYear + 1).ToString("yyyy-MM-dd 00:00:00"),
            _ => DateTime.Now.ToString("yyyy-MM-dd 00:00:00")
        };
    }

    /// <summary>
    /// 获取结束时间
    /// </summary>
    /// <param name="timeType">Day、Week、Month、Year</param>
    /// <param name="now"></param>
    /// <returns></returns>
    public static string GetTimeEndByType(this DateTime now, string timeType = "month")
    {
        switch (timeType.ToLower())
        {
            case "week":
                return now.AddDays((7 - (int)now.DayOfWeek) % 7).ToString("yyyy-MM-dd 23:59:59");
            case "month":
                return now.AddDays(-now.AddMonths(1).Day + 1).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd 23:59:59");
            case "year":
                var time2 = now.AddYears(1);
                return time2.AddDays(-time2.DayOfYear + 1).AddYears(1).AddDays(-1).ToString("yyyy-MM-dd 23:59:59");
            default:
                return DateTime.Now.ToString("yyyy-MM-dd 23:59:59");
        }
    }

    /// <summary>
    /// 当天开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime DayStart(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
    }

    /// <summary>
    /// 当天结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime DayEnd(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);
    }

    /// <summary>
    /// 当月开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime MonthStart(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, 1, 0, 0, 0);
    }

    /// <summary>
    /// 当月结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime MonthEnd(this DateTime now)
    {
        var time = now.AddDays(1 - now.Day).AddMonths(1).AddDays(-1);
        return new DateTime(time.Year, time.Month, time.Day, 23, 59, 59);
    }

    /// <summary>
    /// 当年开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime YearStart(this DateTime now)
    {
        return new DateTime(now.Year, 1, 1, 0, 0, 0);
    }

    /// <summary>
    /// 当年结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime YearEnd(this DateTime now)
    {
        var time = now.AddDays(1 - now.DayOfYear).AddYears(1).AddDays(-1);
        return new DateTime(time.Year, time.Month, time.Day, 23, 59, 59);
    }

    /// <summary>
    /// 时间戳，秒
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static int TimeSeconds(this DateTime time)
    {
        var startTime = new DateTime(1970, 1, 1);
        var span = time - startTime;
        return Convert.ToInt32(span.TotalSeconds);
    }

    /// <summary>
    /// 时间戳，毫秒
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static long TimeMilliseconds(this DateTime time)
    {
        var startTime = new DateTime(1970, 1, 1);
        var span = time - startTime;
        return Convert.ToInt64(span.TotalMilliseconds);
    }

    /// <summary>
    /// 小于某个时间，比某个时间更早
    /// </summary>
    /// <param name="time"></param>
    /// <param name="time2"></param>
    /// <returns></returns>
    public static bool Earlier(this DateTime time, DateTime time2)
    {
        return time.CompareTo(time2) < 0;
    }

    /// <summary>
    /// 大于某个时间，比某个时间更迟
    /// </summary>
    /// <param name="time"></param>
    /// <param name="time2"></param>
    /// <returns></returns>
    public static bool Later(this DateTime time, DateTime time2)
    {
        return time.CompareTo(time2) > 0;
    }
    
    /// <summary>
    /// 格式化时间
    /// </summary>
    /// <param name="ts"></param>
    /// <param name="ignoreMilliseconds">忽略毫秒，默认true，1秒=1000毫秒</param>
    /// <param name="ignoreMicroseconds">忽略微秒，默认true，1毫秒=1000微秒</param>
    /// <returns></returns>
    public static string ToFormatString(this TimeSpan ts, bool ignoreMilliseconds = true, bool ignoreMicroseconds = true)
    {
        var result = "";
        if (ts.Days != 0)
        {
            result += ts.Days + "天";
        }

        if (ts.Hours != 0)
        {
            result += ts.Hours + "小时";
        }

        if (ts.Minutes != 0)
        {
            result += ts.Minutes + "分钟";
        }

        result += ts.Seconds + "秒";
        if (!ignoreMilliseconds)
        {
            result += ts.Milliseconds + "毫秒";
        }

        if (!ignoreMicroseconds)
        {
            result += ts.Microseconds + "微秒";
        }

        return result;
    }
}

public static partial class DateTimeUtil
{
    /// <summary>
    /// 时间戳转时间
    /// </summary>
    /// <param name="seconds">秒</param>
    /// <returns></returns>
    public static DateTime ConvertToDateTime(int seconds)
    {
        var startTime = new DateTime(1970, 1, 1);
        return startTime.AddSeconds(seconds);
    }

    /// <summary>
    /// 时间戳转时间
    /// </summary>
    /// <param name="milliseconds">毫秒</param>
    /// <returns></returns>
    public static DateTime ConvertToDateTime(long milliseconds)
    {
        var startTime = new DateTime(1970, 1, 1);
        return startTime.AddMilliseconds(milliseconds);
    }

    /// <summary>
    /// 字符串转时间,默认yyyy-MM-dd HH:mm:ss
    /// </summary>
    /// <param name="dateStr">时间字符串</param>
    /// <param name="format">格式</param>
    /// <returns></returns>
    public static DateTime? ConvertToDateTime(string dateStr, string? format = null)
    {
        return dateStr.ToDateTime(format);
    }
}
/// <summary>
/// 流扩展
/// </summary>
public static partial class StreamUtil
{
    /// <summary>
    /// 读取成字符串
    /// </summary>
    /// <param name="stream"></param>
    public static async Task<string> ReadAsByteToString(this Stream stream)
    {
        var builder = new StringBuilder();
        var buffer = new byte[4096];
        int readCount;
        while ((readCount = await stream.ReadAsync(buffer)) > 0)
        {
            var str = Encoding.UTF8.GetString(buffer, 0, readCount);
            builder.Append(str);
        }

        return builder.ToString();
    }

    /// <summary>
    /// 读取成字符串
    /// </summary>
    /// <param name="stream"></param>
    public static async Task<string> ReadAsString(this Stream stream)
    {
        //处理body数据
        using MemoryStream memoryStream = new();
        // 复制Body数据到缓存
        await stream.CopyToAsync(memoryStream);
        memoryStream.Position = 0;
        using StreamReader streamReader = new(memoryStream);
        // 读取Body数据
        return await streamReader.ReadToEndAsync();
    }

    /// <summary>
    /// 写入文件
    /// </summary>
    /// <param name="ms"></param>
    /// <param name="path"></param>
    public static void Write(this MemoryStream ms, string path)
    {
        using var fs = new FileStream(path, FileMode.Create, FileAccess.Write);
        var bytes = ms.ToArray();
        fs.Write(bytes, 0, bytes.Length);
        fs.Flush();
    }

    /// <summary>
    /// 通过给定的文件流，判断文件的编码类型 
    /// </summary>
    /// <param name="fs"></param>
    /// <returns></returns>
    public static Encoding GetType(this FileStream fs)
    {
        // var Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
        // var UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
        // var UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM 
        var reVal = Encoding.Default;

        var r = new BinaryReader(fs, Encoding.Default);
        int.TryParse(fs.Length.ToString(), out var i);
        var ss = r.ReadBytes(i);
        if (IsUtf8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF))
        {
            reVal = Encoding.UTF8;
        }
        else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
        {
            reVal = Encoding.BigEndianUnicode;
        }
        else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
        {
            reVal = Encoding.Unicode;
        }

        r.Close();
        return reVal;
    }

    /// <summary>
    /// 判断是否是不带 BOM 的 UTF8 格式 
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    private static bool IsUtf8Bytes(byte[] data)
    {
        var charByteCounter = 1; //计算当前正分析的字符应还有的字节数 
        foreach (var t in data)
        {
            var curByte = t; //当前分析的字节. 
            if (charByteCounter == 1)
            {
                if (curByte >= 0x80)
                {
                    //判断当前 
                    while (((curByte <<= 1) & 0x80) != 0)
                    {
                        charByteCounter++;
                    }

                    //标记位首位若为非0 则至少以2个1开始 如:110 XX XXX...........1111110X 
                    if (charByteCounter == 1 || charByteCounter > 6)
                    {
                        return false;
                    }
                }
            }
            else
            {
                //若是UTF-8 此时第一位必须为1 
                if ((curByte & 0xC0) != 0x80)
                {
                    return false;
                }

                charByteCounter--;
            }
        }

        if (charByteCounter > 1)
        {
            throw new Exception("非预期的byte格式");
        }

        return true;
    }
}

public static partial class StreamUtil{}
/// <summary>
/// 数字相关扩展
/// </summary>
public static partial class NumberUtil
{
    /// <summary>
    /// 进制转换
    /// </summary>
    /// <param name="num">数据</param>
    /// <param name="radix">进制：最大64</param>
    /// <returns></returns>
    public static string ToRadix(this long num, int radix)
    {
        if (radix > 64)
        {
            return "";
        }

        var value = "";
        while (num > 1)
        {
            var index = (int)(num % radix);
            value = RadixCode[index] + value;
            num /= radix;
        }

        return value;
    }

    /// <summary>
    /// 进制解析
    /// </summary>
    /// <param name="value">字符串</param>
    /// <param name="radix">进制：最大64</param>
    /// <returns></returns>
    public static long ParseRadix(this string value, int radix)
    {
        if (radix > 64)
        {
            return 0;
        }

        var num = 0L;
        var step = 1L;
        for (var i = 0; i < value.Length; i++)
        {
            var index = RadixCode.IndexOf(value[value.Length - 1 - i]);
            if (index == -1)
            {
                return 0;
            }

            if (i > 0)
            {
                step *= radix;
            }

            num += index * step;
        }

        return num;
    }

    /// <summary>
    /// 最大64进制
    /// </summary>
    private static readonly List<char> RadixCode = new()
    {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
        'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        '-', '_'
    };
}
public static partial class NumberUtil{}

/// <summary>
/// 对象扩展
/// </summary>
public static partial class ObjectUtil
{
    /// <summary>
    /// 复制对象
    /// </summary>
    /// <param name="model">源类</param>
    /// <param name="deep">深拷贝，默认false</param>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T Copy<T>(this T model, bool deep = false) where T : new()
    {
        if (deep)
        {
            var json = model.Serialize();
            var target = json.Deserialize<T>();
            if (target == null)
            {
                throw CommonUtil.ActionException("对象复制失败");
            }

            return target;
        }

        return CommonUtil.AutoMapping(model, new T());
    }

    /// <summary>
    /// 复制对象
    /// </summary>
    /// <param name="model">源类</param>
    /// <param name="ignores">忽略的字段</param>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T AutoMapping<T>(this object model, params string[] ignores) where T : new()
    {
        return CommonUtil.AutoMapping(model, new T(), ignores);
    }

    /// <summary>
    /// 对象自动赋值
    /// </summary>
    /// <param name="model">源类</param>
    /// <param name="target"></param>
    /// <param name="ignores">忽略的字段</param>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T AutoMapping<T>(this object model, T target, params string[] ignores) where T : new()
    {
        return CommonUtil.AutoMapping(model, target, ignores);
    }

    /// <summary>
    /// 向下转型
    /// </summary>
    /// <param name="model">源类</param>
    /// <typeparam name="TM">源对象</typeparam>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T DownwardTransition<TM, T>(this TM model) where T : TM, new()
    {
        return CommonUtil.AutoMapping(model, new T());
    }

    /// <summary>
    /// JSON序列化，字符串会直接返回字符串
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static string Serialize(this object? obj)
    {
        return obj == null ? "" : obj as string ?? JsonSerializer.Serialize(obj, CommonUtil.AppJsonSerializerOptions);
    }

    /// <summary>
    /// JSON反序列化
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public static T? Deserialize<T>(this string? content)
    {
        if (!string.IsNullOrEmpty(content))
        {
            try
            {
                return JsonSerializer.Deserialize<T>(content, CommonUtil.AppJsonSerializerOptions);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return default;
    }

    /// <summary>
    /// 对象转字典
    /// </summary>
    /// <param name="obj">对象</param>
    /// <returns></returns>
    public static Dictionary<string, object?> ToDictionary(this object obj)
    {
        var dictionary = new Dictionary<string, object?>();
        var properties = obj.GetType().GetProperties();
        foreach (var property in properties)
        {
            try
            {
                var value = property.GetValue(obj, null);
                dictionary.Add(property.Name, value);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return dictionary;
    }

    /// <summary>
    /// 根据属性名获取值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <returns></returns>
    public static object? GetFieldValue(this object obj, string fieldName)
    {
        var propertyInfo = obj.GetType().GetProperty(fieldName);
        if (propertyInfo != null)
        {
            try
            {
                return propertyInfo.GetValue(obj, null);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return default;
    }

    /// <summary>
    /// 根据属性名获取值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <returns></returns>
    public static T? GetFieldValue<TM, T>(this TM obj, string fieldName) where TM : class
    {
        var value = obj.GetFieldValue(fieldName);
        if (value is T t)
        {
            return t;
        }

        return default;
    }

    /// <summary>
    /// 获取值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="propertyInfo">属性</param>
    /// <returns></returns>
    public static object? GetFieldValue(this PropertyInfo? propertyInfo, object obj)
    {
        if (propertyInfo != null)
        {
            try
            {
                return propertyInfo.GetValue(obj, null);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return default;
    }

    /// <summary>
    /// 获取值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="propertyInfo">属性</param>
    /// <returns></returns>
    public static T? GetFieldValue<T>(this PropertyInfo? propertyInfo, object obj)
    {
        var value = propertyInfo.GetFieldValue(obj);
        if (value is T t)
        {
            return t;
        }

        return default;
    }

    /// <summary>
    /// 根据属性名获获取属性类型
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <returns></returns>
    public static Type? GetFieldType<T>(this T obj, string fieldName) where T : class
    {
        var propertyInfo = obj.GetType().GetProperty(fieldName);
        if (propertyInfo != null)
        {
            try
            {
                return propertyInfo.PropertyType;
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return default;
    }

    /// <summary>
    /// 根据属性名设置值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetFieldValue(this object obj, string fieldName, object? value)
    {
        var propertyInfo = obj.GetType().GetProperty(fieldName);
        propertyInfo.SetFieldValue(obj, value);
    }

    /// <summary>
    /// 根据属性名设置值
    /// </summary>
    /// <param name="propertyInfo">属性</param>
    /// <param name="obj">对象</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetFieldValue(this PropertyInfo? propertyInfo, object obj, object? value)
    {
        if (propertyInfo == null) return;
        if (value == null) return;
        try
        {
            object? value2 = null;
            if (propertyInfo.PropertyType != value.GetType())
            {
                if (propertyInfo.PropertyType == typeof(string))
                {
                    value2 = value as string ?? value.ToString();
                }
                else if ((propertyInfo.PropertyType == typeof(DateTime) ||
                          propertyInfo.PropertyType == typeof(DateTime?))
                         && value is not DateTime)
                {
                    value2 = (value?.ToString() ?? "").ToDateTime();
                }
                else if ((propertyInfo.PropertyType == typeof(bool) || propertyInfo.PropertyType == typeof(bool?))
                         && value is not bool)
                {
                    var strVal = value.ToString() ?? "";
                    if (strVal is "是" or "1")
                    {
                        value2 = true;
                    }
                    else
                    {
                        value2 = bool.TryParse(strVal, out var boolVal) && boolVal;
                    }
                }
                else if ((propertyInfo.PropertyType == typeof(int) || propertyInfo.PropertyType == typeof(int?))
                         && value is not int
                         && int.TryParse(value.ToString() ?? "", out var intVal))
                {
                    value2 = intVal;
                }
                else if ((propertyInfo.PropertyType == typeof(double) || propertyInfo.PropertyType == typeof(double?))
                         && value is not double
                         && double.TryParse(value.ToString() ?? "", out var doubleVal))
                {
                    value2 = doubleVal;
                }
                else if ((propertyInfo.PropertyType == typeof(float) || propertyInfo.PropertyType == typeof(float?))
                         && value is not float
                         && float.TryParse(value.ToString() ?? "", out var floatVal))
                {
                    value2 = floatVal;
                }
                else if ((propertyInfo.PropertyType == typeof(decimal) || propertyInfo.PropertyType == typeof(decimal?))
                         && value is not decimal
                         && decimal.TryParse(value.ToString() ?? "", out var decimalVal))
                {
                    value2 = decimalVal;
                }
            }

            value2 ??= value;
            propertyInfo.SetValue(obj, value2, null);
        }
        catch (Exception e)
        {
            e.Message.LogError();
        }
    }

    /// <summary>
    /// 是否是同一种类型，忽略可空类型int与int?返回true。
    /// </summary>
    /// <param name="type"></param>
    /// <param name="type2"></param>
    public static bool IsSameTypeIgnoreNullable(this Type type, Type type2)
    {
        if (type == type2)
        {
            return true;
        }

        var t1Nullable = type.Name.Contains(nameof(Nullable));
        var t2Nullable = type2.Name.Contains(nameof(Nullable));

        if (t1Nullable && !t2Nullable || !t1Nullable && t2Nullable)
        {
            var nullable = t1Nullable ? type : type2;
            var notNullable = t1Nullable ? type2 : type;
            var tmp = Type.GetType($"System.Nullable`1[{notNullable.FullName}]");
            return nullable == tmp;
        }

        return false;
    }
    
    

    /// <summary>
    /// 新增或更新的字段配置
    /// </summary>
    [SuppressMessage("ReSharper", "StringLiteralTypo")]
    private static readonly Dictionary<string, string[]> InitAddAndUpdateCfg = new()
    {
        { "id", new[] { "id", "_id", "Id", "ID" } },
        { "create_user", new[] { "create_user", "createuser", "add_user", "adduser" } },
        {
            "create_time",
            new[]
            {
                "create_time", "createtime", "create_date", "createdate", "insert_time", "inserttime", "insert_date",
                "insertdate", "add_time", "addtime"
            }
        },
        { "update_user", new[] { "update_user", "updateuser", "modify_user", "modifyuser", "modifier" } },
        {
            "update_time",
            new[] { "update_time", "updatetime", "modify_time", "modifytime", "modify_date", "modifydate" }
        },
    };

    /// <summary>
    /// 初始化实体对象，ID为0时初始化创建人和创建时间，ID大于0时初始化修改人合修改时间
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="userId"></param>
    /// <returns>Add返回true，否则返回false</returns>
    public static bool InitAddAndUpdate(this object obj, string? userId = null)
    {
        var infos = obj.GetType().GetProperties();
        var idInfo = infos.First(info => InitAddAndUpdateCfg["id"].Contains(info.Name.ToLower()));
        if (idInfo.GetFieldValue<int>(obj) == 0)
        {
            var createUserInfo =
                infos.FirstOrDefault(info => InitAddAndUpdateCfg["create_user"].Contains(info.Name.ToLower()));
            createUserInfo?.SetFieldValue(obj, userId ?? "");
            var createTimeInfo =
                infos.FirstOrDefault(info => InitAddAndUpdateCfg["create_time"].Contains(info.Name.ToLower()));
            createTimeInfo?.SetFieldValue(obj, CommonUtil.LocalDateTime());
            return true;
        }
        else
        {
            var updateUserInfo =
                infos.FirstOrDefault(info => InitAddAndUpdateCfg["update_user"].Contains(info.Name.ToLower()));
            updateUserInfo?.SetFieldValue(obj, userId ?? "");
            var updateTimeInfo =
                infos.FirstOrDefault(info => InitAddAndUpdateCfg["update_time"].Contains(info.Name.ToLower()));
            updateTimeInfo?.SetFieldValue(obj, CommonUtil.LocalDateTime());
            return false;
        }
    }
}
public static partial class ObjectUtil{}